﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using Pixysoft.Framework.Verifications;
using Pixysoft.Collections;
using System.Threading;

namespace Pixysoft.Framework.Comet.Core
{
    /// <summary>
    /// 每个comet接受者会对应一个cometrequest，保存需要接受的cometmessage
    /// </summary>
    class CometRequest : ICometRequest
    {
        //内部唯一编码
        string requestUid = Pixysoft.Tools.GlobalTimer.Instance.GetUniqueStringSequence();

        //是否已经删除了
        bool isDisposed = false;

        //当前请求是否已经有链接连接上了
        //当有comet链接使用sendercode链接到服务器后，标志位=true；否则=false
        //用于判断用户是否在线，能否发送实时请求
        bool isSubscribed = false;

        //是否持久模式 如果是持久模式 则根据获取时间戳获取新信息 同时不删除消息队列；否则每次删除消息队列
        //持久模式下，在添加新消息的时候，会删除过时的消息
        //持久模式一般用在实时传输
        bool isPersist = false;


        string senderCode;

        //刷新时间戳
        //用于控制链接、请求结束时间戳
        private DateTime startDate = DateTime.MinValue;

        //连接结束时间戳
        //初始化、建立链接的时候刷新
        //用户sendercode判断当前链接是否已经超时，断开comet链接
        private DateTime connectionEndDate = DateTime.MinValue;

        //请求结束时间戳
        //同上
        private DateTime requestEndDate = DateTime.MinValue;

        //sendercode用户最近一次获取消息的时间
        //初始化最小值后 发送方判断接收方是否获取过信息
        //每次获取消息后都会更新
        private DateTime lastPickupDate = DateTime.MinValue;

        /// <summary>
        /// 当前链接的http对象 通过subscribe更新最新的context
        /// </summary>
        HttpContext context = null;

        //最后获取的消息的时间戳
        //接收方获取最新信息的时间戳
        //每次获取消息后都会更新
        private long lastMessageTimeStamp = -1;


        private Queue<ICometMessage> messages = new Queue<ICometMessage>();


        public CometRequest(string sendercode)
        {
            this.senderCode = sendercode;

            RefreshDate();
        }


        public void TransferFrom(ICometRequest request)
        {
            this.senderCode = request.SenderCode;
            this.startDate = request.StartDate;
            this.connectionEndDate = request.ConnectionEndDate;
            this.requestEndDate = request.RequestEndDate;
            this.lastPickupDate = request.LastPickupDate;
            this.lastMessageTimeStamp = request.LastMessageTimeStamp;
            this.AddMessages(request.GetAllMessages());
        }


        public virtual void SetPersisted()
        {
            LoggerHelper.Debug("{0}::set message as persisted.", senderCode);

            this.isPersist = true;
        }

        public virtual void Subscribe(HttpContext context)
        {
            LoggerHelper.Debug("{0}::subscribe message", senderCode);

            isSubscribed = true;

            RefreshDate();
        }

        public virtual void UnSubscribe()
        {
            LoggerHelper.Debug("{0}::unsubscribe message", senderCode);

            isSubscribed = false;
        }

        public virtual void Dispose()
        {
            LoggerHelper.Debug("{0}::dispose message.", senderCode);

            //ClearMessages();

            this.isDisposed = true;
        }

        private void RefreshDate()
        {
            this.startDate = Pixysoft.Tools.GlobalTimer.Instance.GetGlobalTime();

            this.connectionEndDate = this.startDate.AddSeconds(SettingHelper.default_web_connectiontimeout);

            this.requestEndDate = this.startDate.AddSeconds(SettingHelper.default_web_requesttimeout);

            LoggerHelper.Debug("{0}::comet request refresh data, startdate:{1},connectionenddate:{2},requestenddate:{3}",
                senderCode, startDate, connectionEndDate, requestEndDate);
        }


        /// <summary>
        /// 如果是持久数据 则对比时间戳，存在返回； 如果是普通数据，则删除数据后返回。
        /// </summary>
        /// <param name="timestamp"></param>
        /// <returns></returns>
        public virtual ICometMessage GetNextMessage()
        {
            return GetNextMessage(LastMessageTimeStamp);
        }

        /// <summary>
        /// 如果是持久数据 则对比时间戳，存在返回； 如果是普通数据，则删除数据后返回。用于broadcast模式下的判断
        /// </summary>
        /// <param name="timestamp"></param>
        /// <returns></returns>
        public virtual ICometMessage GetNextMessage(long lastMessageTimeStamp)
        {
            LoggerHelper.Debug("{0}::get next message at {1}. messages.count:{2}", senderCode, lastMessageTimeStamp, messages.Count);

            int index = -1;

            if (messages.Count == 0)
            {
                LoggerHelper.Debug("{0}::get next message, no messages, return null", senderCode);

                return null;
            }

            ICometMessage message = null;

            if (IsPersisted)
            {
                foreach (ICometMessage rmessage in messages.ToArray())
                {
                    message = rmessage;

                    if (message.TimeStamp <= lastMessageTimeStamp)
                    {
                        message = null;

                        continue;
                    }

                    LoggerHelper.Debug("{0}:: get next message, persisted, break from search.", senderCode);

                    break;
                }
            }
            else
            {
                while (messages.Count > 0)
                {
                    message = messages.Dequeue();

                    if (message.TimeStamp <= lastMessageTimeStamp)
                    {
                        message = null;

                        continue;
                    }

                    LoggerHelper.Debug("{0}:: get next message, not persisted, message is also dequeued.", senderCode);

                    break;
                }
            }

            if (message != null)
                SetLastMessageTimeStamp(new ICometMessage[] { message });

            UpdateLastPickupDate();

            LoggerHelper.Debug("{0}::get next messages, result:{1}, messages.count:{2}, ispersisted:{3}",
                senderCode, message != null, messages.Count, isPersist);

            return message;
        }

        /// <summary>
        /// 获取全部信息 如果是Persist模式，则同时删除所有信息
        /// </summary>
        /// <returns></returns>
        public virtual ICometMessage[] GetAllMessages()
        {
            ICometMessage[] values = messages.ToArray();

            if (!IsPersisted)
                ClearMessages();

            SetLastMessageTimeStamp(values);

            UpdateLastPickupDate();

            LoggerHelper.Debug("{0}::get all messages, count:{1}", senderCode, messages.Count);

            return values;
        }

        public virtual ICometMessage GetLastMessage()
        {
            if (messages.Count == 0)
            {
                LoggerHelper.Debug("{0}::get last message, no messages, return null.", senderCode);

                return null;
            }

            ICometMessage message = null;

            try
            {
                message = messages.ToArray()[messages.Count - 1];

                LoggerHelper.Debug("{0}::get last message, return last message, count:{1}", senderCode, messages.Count);
            }
            catch
            {
                LoggerHelper.Fatal("error when get first message.");

                return null;
            }

            SetLastMessageTimeStamp(new ICometMessage[] { message });

            UpdateLastPickupDate();

            return message;
        }

        protected void UpdateLastPickupDate()
        {

            this.lastPickupDate = Pixysoft.Tools.GlobalTimer.Instance.GetGlobalTime();

            LoggerHelper.Debug("{0}::update last pickup date. timestamp:{1}.", senderCode, LastPickupDate);
        }

        protected void SetLastMessageTimeStamp(ICometMessage[] messages)
        {
            if (messages == null || messages.Length == 0)
                return;

            ICometMessage message = messages[messages.Length - 1];

            this.lastMessageTimeStamp = message.TimeStamp;

            LoggerHelper.Debug("{0}::set last message timestamp:{1} in message(s).", senderCode, lastMessageTimeStamp);
        }


        /// <summary>
        /// 添加信息 如果是Persist模式，则删除过期信息 由发送方控制
        /// </summary>
        /// <param name="newmessages"></param>
        /// <returns></returns>
        public virtual long AddMessages(ICometMessage[] newmessages)
        {
            LoggerHelper.Debug("{0}::add messages, count:{1}.", senderCode, newmessages.Length);

            int messagecount = messages.Count;

            //如果sort 会导致多线程冲突 所以不实用

            foreach (ICometMessage message in newmessages)
            {
                messages.Enqueue(message);
            }

            if (IsPersisted)
                RemoveExpiredMessages();

            return GetLastMessageTimeStamp(newmessages);
        }

        private ICometMessage[] RemoveExpiredMessages()
        {
            //在persist模式下 添加信息后 会删除过期信息

            List<ICometMessage> list = new List<ICometMessage>();

            while (messages.Count > SettingHelper.defautl_web_requestpersistbuffer)
            {
                list.Add(messages.Dequeue());
            }

            return list.ToArray();
        }

        protected long GetLastMessageTimeStamp(ICometMessage[] messages)
        {
            if (messages == null || messages.Length == 0)
                return -1;

            ICometMessage message = messages[messages.Length - 1];

            return message.TimeStamp;
        }


        public virtual void ClearMessages()
        {
            LoggerHelper.Debug("{0}::clear all messages, count:{1}", senderCode, messages.Count);

            messages.Clear();
        }

        public virtual int MessageCount
        {
            get
            {
                return messages.Count;
            }
        }

        public virtual void Visit(ICometRequestPool pool)
        {
            pool.Visit(senderCode, this);
        }


        /// <summary>
        /// 返回内部标识符
        /// </summary>
        public string RequestUid
        {
            get { return requestUid; }
        }

        /// <summary>
        /// 是否有现有链接
        /// </summary>
        public bool IsSubscribed
        {
            get
            {
                return isSubscribed;
            }
        }

        /// <summary>
        /// 是否已经删除了
        /// </summary>
        public bool IsDisposed
        {
            get { return isDisposed; }
        }

        /// <summary>
        /// 是否持久模式
        /// </summary>
        public bool IsPersisted
        {
            get { return isPersist; }
        }


        public string SenderCode
        {
            get { return senderCode; }
        }

        public DateTime StartDate
        {
            get { return startDate; }
        }

        public DateTime ConnectionEndDate
        {
            get { return connectionEndDate; }
        }

        public DateTime RequestEndDate
        {
            get { return requestEndDate; }
        }

        public DateTime LastPickupDate
        {
            get
            {
                return lastPickupDate;
            }
        }

        public HttpContext Context
        {
            get { return context; }
            set { context = value; }
        }

        public virtual long LastMessageTimeStamp
        {
            get
            {
                return this.lastMessageTimeStamp;
            }
        }
    }
}
